package io.github.chutian0610.sqlparser

import arrow.core.None
import arrow.core.Option
import io.github.chutian0610.sqlparser.dialect.*
import io.github.chutian0610.sqlparser.token.Token
import io.github.chutian0610.sqlparser.token.Tokenizer
import org.junit.jupiter.api.Assertions.assertEquals

/**
 * Returns all supported dialects.
 */
val ALL_DIALECTS = listOf(
    GenericDialect(),
    ClickHouse(),
    Hive(),
    MySQL(),
    PostgreSQL(),
    SQLite()
)

fun allDialects() = TestedDialects.new(ALL_DIALECTS)
fun allDialectsWhen(condition: (Dialect) -> Boolean) = TestedDialects.new(ALL_DIALECTS.filter(condition))
fun allDialectsExcept(condition: (Dialect) -> Boolean) = TestedDialects.new(ALL_DIALECTS.filterNot(condition))

class TestedDialects(
    val dialects: List<Dialect>,
    val option: Option<SqlParserOption>
) {
    companion object {
        fun new(dialects: List<Dialect>) = TestedDialects(dialects, None)
    }

    fun tokenizesExpect(sql: String, expectedTokens: List<Token>) {
        if (dialects.isEmpty()) {
            throw IllegalArgumentException("No dialects to test")
        }
        dialects.forEach { dialect ->
            val tokenizer = Tokenizer.new(dialect)
            if (option.isSome()) {
                tokenizer.withUnescape(requireNotNull(option.getOrNull()).unescape)
            }
            val tokens = requireNotNull(tokenizer.tokenize(sql).getOrNull())
            assertEquals(expectedTokens, tokens, "Tokenized differently for ${dialect.dialectName()}")
        }
    }
}

data class TestCase(
    val sql: String,
    val expectedTokens: List<Token>
)
